package cn.lamplet.service.writepacket.impl;

import cn.lamplet.dao.DaoSupport;
import cn.lamplet.entity.Page;
import cn.lamplet.service.kccu.impl.KCCUServiceImpl;
import cn.lamplet.service.otafile.OtaFileManager;
import cn.lamplet.service.system.file.FileManager;
import cn.lamplet.service.writepacket.WritePacketManager;
import cn.lamplet.util.Const;
import cn.lamplet.util.PageData;
import cn.lamplet.util.PathUtil;
import cn.lamplet.util.StringUtil;
import cn.lamplet.util.kccu.OtaBin;
import cn.lamplet.util.kccu.OtaDto;
import cn.lamplet.util.kccu.ParseId;
import cn.lamplet.util.lindeOSS.SASOSSUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;


/**
 * @author chengshixin
 */
@Service("writePacketService")
public class WritePacketService implements WritePacketManager {

    private final Logger logger = LoggerFactory.getLogger(KCCUServiceImpl.class);

    @Resource(name = "daoSupport")
    private DaoSupport dao;

    @Resource(name = "fileService")
    private FileManager fileService;

    @Resource(name = "otaFileService")
    private OtaFileManager otaFileService;

    @Override
    public List<PageData> list(Page page) throws Exception {
        return (List<PageData>) dao.findForList("WritePacketMapper.datalistPage", page);
    }

    @Override
    public List<PageData> listAll(PageData pd) throws Exception {
        return null;
    }

    @Override
    public int add(PageData pd) throws Exception {
        // 根据表单提交的文件名查询是否有重名
        PageData byFileName = findByFileName(pd);
        if (null != byFileName) {
            return 4;
        }
        // ota文件名称
        String otaName = pd.getString("file_name");

        String fileType = pd.getString("file_type");
        // 文件id
        List<String> pk_file = Arrays.asList(pd.getString("pk_file").split(","));
        // 根据上传的文件id，查询本次上传的文件
        List<PageData> fileList = fileService.findByIds(pk_file);
        List<Map<String, String>> fileUrlList = new ArrayList<>();
        Map<String, String> fileUrlMap = null;
        int res = 0;
        if (null == fileList) {
            return 0;
        }
        List<String> fileTypeList = new ArrayList<>();
        // 将文件类型转换为大写
        for (PageData pageData : fileList) {
            fileTypeList.add(pageData.getString("file_type").toUpperCase());
        }
        // OTA = 0、合成OTA = 1
        String HCOTA = "1";
        if (fileType.equals(HCOTA)) {
            String idFile = ".ID";
            String hexFile = ".HEX";
            if (!fileTypeList.contains(idFile) || !fileTypeList.contains(hexFile)) {
                return 2;
            }
            String idFileName = "";
            String parFileName = "";
            String segFileName = "";
            String hexFileName = "";

            byte[] idBytes = new byte[0];
            byte[] parBytes = new byte[0];
            byte[] segBytes = new byte[0];
            byte[] hexBytes = new byte[0];
            Map<String, byte[]> fileToInputStream = new HashMap<>();
            for (PageData file : fileList) {
                String file_name = file.get("file_name").toString();
                String file_type = file.get("file_type").toString();
                String file_url = file.get("file_url").toString();
                String filePath = PathUtil.getWebAppPath() + Const.FILEPATHFILE + file_url;
                File file1 = new File(filePath);
                switch (file_type) {
                    case ".id":
                        idFileName = file_name.substring(0, file_name.lastIndexOf("."));
                        try (InputStream fis = new FileInputStream(file1)) {
                            idBytes = new byte[fis.available()];
                            // 将文件内容读入字节数组中
                            fis.read(idBytes);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        break;
                    case ".par":
                        parFileName = file_name;
                        try (InputStream fis = new FileInputStream(file1)) {
                            parBytes = new byte[fis.available()];
                            // 将文件内容读入字节数组中
                            fis.read(parBytes);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        fileToInputStream.put(parFileName, parBytes);
                        break;
                    case ".seg":
                        segFileName = file_name;
                        try (InputStream fis = new FileInputStream(file1)) {
                            segBytes = new byte[fis.available()];
                            // 将文件内容读入字节数组中
                            fis.read(segBytes);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        fileToInputStream.put(segFileName, segBytes);
                        break;
                    case ".hex":
                        hexFileName = file_name;
                        try (InputStream fis = new FileInputStream(file1)) {
                            hexBytes = new byte[fis.available()];
                            // 将文件内容读入字节数组中
                            fis.read(hexBytes);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                        fileToInputStream.put(hexFileName, hexBytes);
                        break;
                    default:
                }
            }
            OtaBin otaBin = new OtaBin();
            logger.info("解析id文件开始");
            ParseId parseId = otaBin.parseIdFile(new ByteArrayInputStream(idBytes));
            logger.info("合成OTA文件开始");
            OtaDto otaDto = otaBin.createBin(idFileName, parseId, fileToInputStream);
            InputStream inputStream = otaDto.getInputStream();

            byte[] otaFileBytes = new byte[OtaBin.otaBinLength];
            inputStream.read(otaFileBytes);
            logger.info("上传OTA文件开始");
            String otaFileUrl = SASOSSUtil.upload(new ByteArrayInputStream(otaFileBytes), otaName + ".ota", (long) otaFileBytes.length, "keys-ota");
            logger.info("文件地址,{}", otaFileUrl);
            if (StringUtil.isNotBlank(otaFileUrl)) {
                // OTA文件
                fileUrlMap = new HashMap<>();
                fileUrlMap.put("fileType", "ota");
                fileUrlMap.put("fileName", otaName + ".ota");
                fileUrlMap.put("fileUrl", otaFileUrl);
                fileUrlMap.put("fileSize", (otaFileBytes.length / 1024) + "");
                fileUrlMap.put("fileLength", otaFileBytes.length + "");
                fileUrlList.add(fileUrlMap);

                // 上传id文件
                fileUrlMap = new HashMap<>();
                String idFileUrl = SASOSSUtil.upload(new ByteArrayInputStream(idBytes), idFileName + ".id", (long) idBytes.length, "keys-ota");
                fileUrlMap.put("fileType", "id");
                fileUrlMap.put("fileName", idFileName + ".id");
                fileUrlMap.put("fileUrl", idFileUrl);
                fileUrlMap.put("fileSize", (idBytes.length / 1024) + "");
                fileUrlMap.put("fileLength", idBytes.length + "");
                fileUrlList.add(fileUrlMap);

                for (Map.Entry<String, byte[]> entry : fileToInputStream.entrySet()) {
                    logger.info("key.{}", entry.getKey());
                    String fileUrl = SASOSSUtil.upload(new ByteArrayInputStream(entry.getValue()), entry.getKey(), (long) entry.getValue().length, "keys-ota");
                    fileUrlMap = new HashMap<>();
                    fileUrlMap.put("fileName", entry.getKey());
                    fileUrlMap.put("fileUrl", fileUrl);
                    fileUrlMap.put("fileType", entry.getKey().substring(entry.getKey().lastIndexOf(".") + 1));
                    fileUrlMap.put("fileSize", (entry.getValue().length / 1024) + "");
                    fileUrlMap.put("fileLength", entry.getValue().length + "");
                    fileUrlList.add(fileUrlMap);
                }
                res = (int) dao.save("WritePacketMapper.add", pd);

            }

        }
        else {
            // OTA，如果不包含OTA文件，提示错误
            String otaFileSuffix = ".OTA";
            if (!fileTypeList.contains(otaFileSuffix)) {
                return 3;
            }
            for (PageData file : fileList) {

                String fileName = file.get("file_name").toString().substring(0, file.get("file_name").toString().lastIndexOf(".")) + ".ota";

                // 文件类型不是OTA，就继续下一次遍历
                if (!file.getString("file_type").toUpperCase().equals(otaFileSuffix)) {
                    continue;
                }
                String filePath = PathUtil.getWebAppPath() + Const.FILEPATHFILE + file.get("file_url");
                File otaFile = new File(filePath);
                byte[] otaFileBytes = new byte[0];
                try (InputStream fis = new FileInputStream(otaFile)) {
                    otaFileBytes = new byte[fis.available()];
                    // 将文件内容读入字节数组中
                    fis.read(otaFileBytes);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                String otaFileUrl = SASOSSUtil.upload(new ByteArrayInputStream(otaFileBytes), otaName + otaFileSuffix.toLowerCase(), (long) otaFileBytes.length, "keys-ota");
                fileUrlMap = new HashMap<>();
                // 添加后缀
                fileUrlMap.put("fileName", otaName + otaFileSuffix.toLowerCase());
                fileUrlMap.put("fileUrl", otaFileUrl);
                fileUrlMap.put("fileType", fileName.substring(fileName.lastIndexOf(".") + 1));
                fileUrlMap.put("fileSize", (otaFileBytes.length / 1024) + "");
                fileUrlMap.put("fileLength", otaFileBytes.length + "");
                fileUrlList.add(fileUrlMap);
                // 只上传一个OTA文件
                break;
            }
            res = (int) dao.save("WritePacketMapper.add", pd);
        }
        if (res > 0) {
            PageData params = null;
            for (Map<String, String> map : fileUrlList) {
                params = new PageData();
                params.put("file_name", map.get("fileName"));
                params.put("file_type", map.get("fileType"));
                params.put("write_packet_id", pd.get("id"));
                params.put("file_url", map.get("fileUrl"));
                params.put("file_size", formatFileSize(map.get("fileSize")));
                params.put("file_length", map.get("fileLength"));
                res = otaFileService.add(params);
            }
        }
        return res;
    }

    private String formatFileSize(String fileSize) {
        if("0".equals(fileSize)) {
            return "1KB";
        }
        BigDecimal jz = new BigDecimal("1024");
        BigDecimal target = new BigDecimal(fileSize);
        if (target.compareTo(jz) == 0) {
            return "1MB";
        } else if (target.compareTo(jz) == -1) {
            return fileSize + "KB";
        } else {
            BigDecimal divide = target.divide(jz).setScale(2, BigDecimal.ROUND_HALF_UP);
            return divide.toString() + "MB";
        }
    }

    @Override
    public PageData findById_update(PageData pd) throws Exception {
        return (PageData) dao.findForObject("WritePacketMapper.findById_update", pd);
    }

    @Override
    public void update(PageData pd) throws Exception {
        dao.update("WritePacketMapper.update", pd);
    }

    @Override
    public int delete(PageData pd) throws Exception {
        return (int) dao.update("WritePacketMapper.delete_0", pd);
    }

    /**
     * 根据ota记录id查询关联的文件
     *
     * @param pd
     * @return
     * @throws Exception
     */
    @Override
    public List<PageData> findOtaFileById(PageData pd) throws Exception {
        return (List<PageData>) dao.findForList("WritePacketMapper.findOtaFileById", pd);
    }

    /**
     * 根据名称精确查找
     *
     * @param pd
     * @return
     * @throws Exception
     */
    @Override
    public PageData findByFileName(PageData pd) throws Exception {
        return (PageData) dao.findForObject("WritePacketMapper.findByFileName", pd);
    }

    /**
     * 获取OTA文件列表
     *
     * @param page
     * @return
     * @throws Exception
     */
    @Override
    public List<PageData> findOtaList(Page page) throws Exception {
        return (List<PageData>) dao.findForList("WritePacketMapper.datalistPage1", page);
    }

    /**
     * 检查OTA名称是否重复
     * @param pd
     * @return
     * @throws Exception
     */
    @Override
    public int checkOtaFileName(PageData pd) throws Exception {
        List<PageData> list = (List<PageData>) dao.findForList("WritePacketMapper.checkOtaFileName", pd);
        if(list.size() == 0){
            return 1;
        }
        String fileId = StringUtil.isBlank(pd.getString("fileId")) ? null : pd.getString("fileId");
        String fileName = StringUtil.isBlank(pd.getString("fileName")) ? null : pd.getString("fileName");

        // 入参的文件id不为空，说明是修改
        if(null != fileId){
            // 传递的id和数据库中查询的id一样，说明是修改
            String currentFileName = list.get(0).getString("file_name");
            String currentFileId = list.get(0).getString("id");

            if(fileName != null && fileName.equalsIgnoreCase(currentFileName) && fileId.equalsIgnoreCase(currentFileId)){
                return 1;
            }
        }
        // 入参id为空，说明是新增
        else {
            for (PageData pageData : list) {
                if(null == fileName || fileName.equalsIgnoreCase(pageData.getString("file_name"))){
                    return 0;
                }
            }
            return 1;
        }
        return 0;
    }
}
